---
title: API
---
import { Step, Steps } from 'fumadocs-ui/components/steps';
import { TypeTable } from 'fumadocs-ui/components/type-table';
import {Property} from "fumadocs-openapi/ui"


<Callout>
  This document only covers v2 of the Unkey API. The v1 API on Cloudflare Workers is deprecated and will be removed in the future. It was too hard to selfhost anyways.
</Callout>

Our API runs on AWS containers, in multiple regions behind a global load balancer to ensure high availability and low latency.


The source code is available on [GitHub](https://github.com/unkeyed/unkey/tree/main/go/cmd/api).

## Quickstart

To get started, you need [go1.24+](https://go.dev/dl/) installed on your machine.

<Steps>

<Step>
  ### Clone the repository:

```bash
git clone git@github.com:unkeyed/unkey.git
cd unkey/go
```
</Step>

<Step>
  ### Build the binary:

```bash
go build -o unkey .
```
</Step>

<Step>
  ### Run the binary:

```bash
unkey api --database-primary="mysql://unkey:password@tcp(localhost:3306)/unkey?parseTime=true"
```

You should now be able to access the API at

```bash
$ curl http://localhost:7070/v2/liveness
{"message":"we're cooking"}%
```

By default, the API uses HTTP. To enable HTTPS with TLS, provide certificate and key files using the `--tls-cert-file` and `--tls-key-file` flags:

```bash
unkey api \
  --database-primary="mysql://unkey:password@tcp(localhost:3306)/unkey?parseTime=true" \
  --tls-cert-file="/path/to/server.crt" \
  --tls-key-file="/path/to/server.key"
```

Then access it with HTTPS:

```bash
$ curl https://localhost:7070/v2/liveness
{"message":"we're cooking"}%
```
</Step>



</Steps>

## Configuration


You can configure the Unkey API using command-line flags or environment variables. For each flag shown below, there's an equivalent environment variable.

For example, `--http-port=8080` can also be set using the environment variable `UNKEY_HTTP_PORT=8080`.

### Basic Configuration

These options control the fundamental behavior of the API server.


<Property name="--platform" type="string" required={false}>
  Identifies the cloud platform where this node is running. This information is primarily used for logging, metrics, and debugging purposes.

  **Environment variable:** `UNKEY_PLATFORM`

  **Examples:**
  - `--platform=aws` - When running on Amazon Web Services
  - `--platform=gcp` - When running on Google Cloud Platform
  - `--platform=hetzner` - When running on Hetzner Cloud
  - `--platform=docker` - When running in Docker (e.g., local or Docker Compose)
</Property>

<Property name="--image" type="string" required={false}>
  Container image identifier for this node. This information is used for logging, metrics, and helps with tracking which version of the application is running.

  **Environment variable:** `UNKEY_IMAGE`

  **Examples:**
  - `--image=ghcr.io/unkeyed/unkey:latest` - Latest image from GitHub Container Registry
  - `--image=ghcr.io/unkeyed/unkey:v1.2.3` - Specific version of the image
</Property>

<Property name="--http-port | UNKEY_HTTP_PORT" type="int" default="7070" required={false}>
  Port for the API server to listen on for HTTP or HTTPS connections. When TLS is configured (using --tls-cert-file and --tls-key-file), the server will use HTTPS on this port. Otherwise, it will use HTTP. This port must be accessible by all clients that will interact with the API. In containerized environments, ensure this port is properly exposed.

  **Examples:**
  - `--http-port=7070` - Default port for HTTP
  - `--http-port=443` - Standard HTTPS port (when using TLS)
  - `--http-port=8443` - Common alternative HTTPS port (when using TLS)
</Property>

<Property name="--test-mode | UNKEY_TEST_MODE" type="boolean" defaultValue={false} required={false}>
  Enable test mode. This option is designed for testing environments and should NOT be used in production. When enabled, the server may trust client inputs blindly, potentially bypassing security checks.

  The server logs a warning when started with this flag enabled.

  **Examples:**
  - `--test-mode=true` - Enable test mode for testing environments
  - `--test-mode=false` - Normal operation mode (default, suitable for production)
</Property>

<Property name="--region | UNKEY_REGION" type="string" defaultValue="unknown" required={false}>
  Geographic region identifier where this node is deployed. Used for logging, metrics categorization, and can affect routing decisions in multi-region setups.

  **Examples:**
  - `--region=us-east-1` - AWS US East (N. Virginia)
  - `--region=eu-west-1` - AWS Europe (Ireland)
  - `--region=us-central1` - GCP US Central
  - `--region=dev-local` - For local development environments
</Property>

<Property name="--instance-id | UNKEY_INSTANCE_ID" type="string" required={false}>
  Unique identifier for this instance. This identifier is used in logs, metrics, and for identifying this specific instance of the API server. If not provided, a random ID with a unique prefix will be auto-generated.

  For persistent instances, setting a consistent ID can help with log correlation and tracking instance-specific issues over time.

  **Examples:**
  - `--instance-id=api-prod-1` - First production API instance
  - `--instance-id=api-us-east-001` - API instance in US East region
</Property>

## Database Configuration

The Unkey API requires a MySQL database for storing keys and configuration. For global deployments, a read replica endpoint can be configured to offload read operations.

<Property name="--database-primary | UNKEY_DATABASE_PRIMARY" type="string" required={true}>
  Primary database connection string for read and write operations. This MySQL database stores all persistent data including API keys, workspaces, and configuration. It is required for all deployments.

  For production use, ensure the database has proper backup procedures in place. Unkey is using [PlanetScale](https://planetscale.com/)

  **Examples:**
  - `--database-primary=root:password@localhost:3306/unkey?parseTime=true` - Local MySQL for development
  - `--database-primary=nx...4c:pscale_pw_...va@tcp(aws.connect.psdb.cloud)/unkey?tls=true&interpolateParams=true&parseTime=true` - PlanetScale connection
</Property>

<Property name="--database-replica | UNKEY_DATABASE_REPLICA" type="string" required={false}>
  Optional read-replica database connection string for read operations. When provided, most read operations will be directed to this read replica, reducing load on the primary database and latency for users.

  This is recommended for high-traffic deployments to improve performance and scalability. The read replica must be a valid MySQL read replica of the primary database.

  Unkey is using [PlanetScales](https://planetscale.com/) global read replica endpoint.

  **Examples:**
  - `--database-replica=root:password@localhost:3306/unkey?parseTime=true` - Local MySQL for development
  - `--database-replica=nx...4c:pscale_pw_...va@tcp(aws.connect.psdb.cloud)/unkey?tls=true&interpolateParams=true&parseTime=true` - PlanetScale connection
</Property>

## Analytics & Monitoring

These options configure analytics storage and observability for the Unkey API.

<Property name="--clickhouse-url | UNKEY_CLICKHOUSE_URL" type="string" required={false}>
  ClickHouse database connection string for analytics. ClickHouse is used for storing high-volume event data like API key validations, http request logs and historically aggregated analytics.

  This is optional but highly recommended for production environments. If not provided, analytical capabilities will be omitted but core key validation will still function.


  **Examples:**
  - `--clickhouse-url=clickhouse://localhost:9000/unkey`
  - `--clickhouse-url=clickhouse://user:password@clickhouse.example.com:9000/unkey`
  - `--clickhouse-url=clickhouse://default:password@clickhouse.default.svc.cluster.local:9000/unkey?secure=true`
</Property>

<Property name="--otel | UNKEY_OTEL" type="boolean" defaultValue={false} required={false}>
  Enable OpenTelemetry. The Unkey API will collect and export telemetry data (metrics, traces, and logs) using the OpenTelemetry protocol.

  When this flag is set to true, the following standard OpenTelemetry environment variables are used to configure the exporter:

  - `OTEL_EXPORTER_OTLP_ENDPOINT`: The URL of your OpenTelemetry collector
  - `OTEL_EXPORTER_OTLP_PROTOCOL`: The protocol to use (http/protobuf or grpc)
  - `OTEL_EXPORTER_OTLP_HEADERS`: Headers for authentication (e.g., "authorization=Bearer \<token\>")

  Using these standard variables ensures compatibility with OpenTelemetry documentation and tools. For detailed configuration information, see the [official OpenTelemetry documentation](https://grafana.com/docs/grafana-cloud/send-data/otlp/send-data-otlp/).

  **Examples:**

  ```bash
  # Enable OpenTelemetry
  export UNKEY_OTEL=true
  export OTEL_EXPORTER_OTLP_ENDPOINT="https://otlp-gateway-prod-us-east-0.grafana.net/otlp"
  export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
  export OTEL_EXPORTER_OTLP_HEADERS="authorization=Basic ..."

  # Or as command-line flags
  unkey api --otel=true"
  ```
</Property>

<Property name="--otel-trace-sampling-rate | UNKEY_OTEL_TRACE_SAMPLING_RATE" type="float64" defaultValue={0.25} required={false}>
  Sets the sampling rate for OpenTelemetry traces as a decimal value between 0.0 and 1.0. This controls what percentage of traces will be collected and exported, helping to balance observability needs with performance and cost considerations.

  - 0.0 means no traces are sampled (0%)
  - 0.25 means 25% of traces are sampled (default)
  - 1.0 means all traces are sampled (100%)

  Lower sampling rates reduce overhead and storage costs but provide less visibility. Higher rates give more comprehensive data but increase resource usage and costs.

  This setting only takes effect when OpenTelemetry is enabled with `--otel=true`.

  **Examples:**
  - `--otel-trace-sampling-rate=0.1` - Sample 10% of traces
  - `--otel-trace-sampling-rate=0.25` - Sample 25% of traces (default)
  - `--otel-trace-sampling-rate=1.0` - Sample all traces

  **Environment variable:** `UNKEY_OTEL_TRACE_SAMPLING_RATE`
</Property>

<Property name="--prometheus-port | UNKEY_PROMETHEUS_PORT" type="number" defaultValue={0} required={false}>
  Port for exposing Prometheus metrics. When set to a value greater than 0, the API server will expose a `/metrics` endpoint on the specified port for scraping by Prometheus. Setting this to 0 disables the Prometheus metrics endpoint.

  This is useful for monitoring the API server's performance and health in production environments. The metrics include information about HTTP requests, database operations, cache performance, and more.

  **Examples:**
  - `--prometheus-port=0` - Disable Prometheus metrics endpoint (default)
  - `--prometheus-port=9090` - Expose metrics on port 9090
  - `--prometheus-port=9100` - Standard port used by node_exporter

  **Environment variable:** `UNKEY_PROMETHEUS_PORT`
</Property>

<Property name="--color | UNKEY_COLOR" type="boolean" defaultValue={true} required={false}>
  Enable ANSI color codes in log output. When enabled, log output will include ANSI color escape sequences to highlight different log levels, timestamps, and other components of the log messages.

  This is useful for local development and debugging but may need to be disabled in production environments where logs are collected by systems that may not properly handle ANSI escape sequences.

  **Examples:**
  - `--color=true` - Enable colored logs (default)
  - `--color=false` - Disable colored logs (for environments that don't handle ANSI colors well)
</Property>

## Redis Configuration

<Property name="--redis-url | UNKEY_REDIS_URL" type="string" required={false}>
  Redis connection string for rate-limiting and distributed counters. Redis is used to maintain counters for rate limiting and other features that require distributed state.

  While not strictly required, Redis is recommended for production deployments, especially when running multiple instances of the API server, to ensure consistent rate limiting.

  **Examples:**
  - `--redis-url=redis://localhost:6379/0`
  - `--redis-url=redis://user:password@redis.example.com:6379/0`
  - `--redis-url=redis://user:password@redis-master.default.svc.cluster.local:6379/0?tls=true`
</Property>

## TLS Configuration

These options allow you to enable HTTPS by providing TLS certificate and key files. Both flags must be provided together to enable HTTPS.

<Property name="--tls-cert-file | UNKEY_TLS_CERT_FILE" type="string" required={false}>
  Path to the TLS certificate file in PEM format. This certificate will be used for securing HTTPS connections to the API server.
  
  For production use, this should be a certificate signed by a trusted certificate authority (CA). For development or internal use, a self-signed certificate may be sufficient.

  This flag must be used together with `--tls-key-file`. If either is provided without the other, the server will return an error at startup.

  **Examples:**
  - `--tls-cert-file=/path/to/server.crt` - Path to certificate file
  - `--tls-cert-file=/etc/ssl/certs/unkey-api.crt` - Standard location in Linux systems
</Property>

<Property name="--tls-key-file | UNKEY_TLS_KEY_FILE" type="string" required={false}>
  Path to the TLS private key file in PEM format. This key must correspond to the certificate provided in `--tls-cert-file`.
  
  The private key file should be kept secure with restricted permissions (0600 recommended). Never commit private keys to source control.

  **Examples:**
  - `--tls-key-file=/path/to/server.key` - Path to key file
  - `--tls-key-file=/etc/ssl/private/unkey-api.key` - Standard location in Linux systems
</Property>

## Deployment Examples

### Single-Node (HTTP)

```bash
unkey api \
  --database-primary="mysql://root:password@localhost:3306/unkey?parseTime=true" \
  --color=true \
  --http-port=8080 \
  --region=dev-local
```

### Single-Node (HTTPS)

```bash
unkey api \
  --database-primary="mysql://root:password@localhost:3306/unkey?parseTime=true" \
  --color=true \
  --http-port=8443 \
  --tls-cert-file="/path/to/server.crt" \
  --tls-key-file="/path/to/server.key" \
  --region=dev-local
```

### Docker Compose Setup

```yaml
services:
  api:
    deploy:
      replicas: 3
      endpoint_mode: vip
    command: ["api"]
    image: ghcr.io/unkeyed/unkey:latest
    depends_on:
      - mysql
      - redis
      - clickhouse
    environment:
      UNKEY_HTTP_PORT: 7070
      UNKEY_PLATFORM: "docker"
      UNKEY_IMAGE: "ghcr.io/unkeyed/unkey:latest"
      UNKEY_REDIS_URL: "redis://redis:6379"
      UNKEY_DATABASE_PRIMARY_DSN: "mysql://unkey:password@tcp(mysql:3900)/unkey?parseTime=true"
      UNKEY_CLICKHOUSE_URL: "clickhouse://default:password@clickhouse:9000"
      UNKEY_PROMETHEUS_PORT: 9090
      # Uncomment for HTTPS:
      # UNKEY_TLS_CERT_FILE: "/etc/ssl/certs/unkey-api.crt"
      # UNKEY_TLS_KEY_FILE: "/etc/ssl/private/unkey-api.key"
```


### AWS ECS Production Example

```bash
unkey api \
  --platform="aws" \
  --region="us-east-1" \
  --image="ghcr.io/unkeyed/unkey:latest" \
  --redis-url="redis://user:password@redis.example.com:6379" \
  --database-primary="mysql://user:password@primary.mysql.example.com:3306/unkey?parseTime=true" \
  --database-readonly-replica="mysql://readonly:password@replica.mysql.example.com:3306/unkey?parseTime=true" \
  --clickhouse-url="clickhouse://user:password@clickhouse.example.com:9000/unkey" \
  --otel=true \
  --prometheus-port=9090
```

### Production with HTTPS

```bash
unkey api \
  --platform="aws" \
  --region="us-east-1" \
  --image="ghcr.io/unkeyed/unkey:latest" \
  --database-primary="mysql://user:password@primary.mysql.example.com:3306/unkey?parseTime=true" \
  --redis-url="redis://user:password@redis.example.com:6379" \
  --tls-cert-file="/etc/ssl/certs/unkey-api.crt" \
  --tls-key-file="/etc/ssl/private/unkey-api.key" \
  --http-port=443
```
